home *** CD-ROM | disk | FTP | other *** search
- ////////////////////////////////////////////////////////////////
- // File - PCI_DMA.C
- //
- // This is a skeleton driver for a PCI card with Bus Master DMA.
- // The driver implemets PCI detection, accessing memory mapped
- // ranges on the card, and interrupt handler installation.
- //
- // It is recommended to take a look at real-world samples of
- // PCI Bus Master DMA, in /windrvr/amcc/lib/amcclib.c and
- // /windrvr/v3/lib/pbclib.c.
- //
- ////////////////////////////////////////////////////////////////
-
- #include "../../include/windrvr.h"
- #include <stdio.h>
-
- // put your vendor_id & device_id here
- enum {MY_VENDOR_ID = 0x1201};
- enum {MY_DEVICE_ID = 0x0001};
-
- // put the offset of the card's register for programing DMA here
- enum {MY_REG_DMA_STATUS = 0x10};
- enum {MY_REG_DMA_PAGES = 0x100};
-
- void MY_CardMainDriver()
- {
- // put your device driver code here
- }
-
-
- /////////////////////////////////////
- // global variables section G_xxxx
- /////////////////////////////////////
- enum {INVALID_RES = 0xffff};
-
- HANDLE hWD;
- WD_CARD_REGISTER G_cardReg;
-
- // index to resource in card of memory region & interrupt
- // if you have more than one memory region, interrupt or have an IO range,
- // add more indexes here, and locate them in IO_DetectCardElements() function.
- DWORD G_resMemory;
- // base address for memory mapped region
- DWORD G_baseMemory;
- DWORD G_baseMemoryTrns;
-
- void IO_Open()
- {
- WD_VERSION ver;
-
- hWD = INVALID_HANDLE_VALUE;
- hWD = WD_Open();
- // Check whether handle is valid and version OK
- if (hWD==INVALID_HANDLE_VALUE)
- {
- printf("Failed opening " WD_PROD_NAME " device\n");
- exit(1);
- }
- BZERO(ver);
- WD_Version(hWD,&ver);
- if (ver.dwVer<WD_VER)
- {
- printf("Incorrect " WD_PROD_NAME " version\n");
- WD_Close(hWD);
- exit(1);
- }
-
- G_cardReg.hCard = 0;
- }
-
- // IO_DetectCardElements() scans the card recourses (Interrupts, IO & memory mapped regions)
- // and sets IO_ResInterrupt & IO_ResMemory to point to the correct element number
- void IO_DetectCardElements()
- {
- DWORD i;
-
- G_resMemory = INVALID_RES;
-
- for (i=0; i<G_cardReg.Card.dwItems; i++)
- {
- switch(G_cardReg.Card.Item[i].item)
- {
- case ITEM_INTERRUPT:
- printf("error - Card has an Interrupt\n");
- exit(1);
- break;
- case ITEM_MEMORY:
- if (G_resMemory==INVALID_RES)
- G_resMemory = i;
- else
- {
- printf("error - Card has more than one memory region\n");
- exit(1);
- }
- break;
- case ITEM_IO:
- printf("error - Card has an IO ragne\n");
- exit(1);
- break;
- }
- }
-
- if (G_resMemory==INVALID_RES)
- {
- printf("Memory region not found\n");
- exit(1);
- }
- }
-
- // IO_DetectCard() scans the PCI bus & detect the card
- void IO_DetectCard()
- {
- WD_PCI_SCAN_CARDS pciScan;
- WD_PCI_CARD_INFO pciCardInfo;
-
- BZERO(pciScan);
- pciScan.searchId.dwVendorId = MY_VENDOR_ID;
- pciScan.searchId.dwDeviceId = MY_DEVICE_ID;
- WD_PciScanCards (hWD, &pciScan);
- if (pciScan.dwCards==0) // Found at least one card
- {
- printf("Could not find PCI card\n");
- exit(1);
- }
-
- BZERO(pciCardInfo);
- pciCardInfo.pciSlot = pciScan.cardSlot[0];
- WD_PciGetCardInfo (hWD, &pciCardInfo);
-
- // the info for Card comes from WD_PciGetCardInfo()
- // for PCI cards. for ISA cards the information has to be
- // set by the user (IO/memory address & interrupt number).
- BZERO(G_cardReg);
- G_cardReg.Card = pciCardInfo.Card;
- IO_DetectCardElements();
- G_cardReg.fCheckLockOnly = FALSE;
- WD_CardRegister (hWD, &G_cardReg);
- if (G_cardReg.hCard==0)
- {
- printf ("Failed locking device\n");
- exit(1);
- }
-
- G_baseMemory = G_cardReg.Card.Item[G_resMemory].I.Mem.dwUserDirectAddr;
- G_baseMemoryTrns = G_cardReg.Card.Item[G_resMemory].I.Mem.dwTransAddr;
- }
-
- void IO_Close()
- {
- // unregister card
- if (G_cardReg.hCard)
- WD_CardUnregister(hWD, &G_cardReg);
-
- // close WinDriver
- WD_Close(hWD);
- }
-
- // performs a single 32 bit read from memory mapped range
- DWORD IO_Read32BitRegister(DWORD dwAddr)
- {
- PDWORD pDW = (PDWORD) (G_baseMemory + dwAddr);
- return *pDW;
- }
-
- // performs a single 32 bit write to memory mapped range
- void IO_Write32BitRegister(DWORD dwAddr, DWORD dwData)
- {
- PDWORD pDW = (PDWORD) (G_baseMemory + dwAddr);
- *pDW = dwData;
- }
-
- // transfer data to/from PCI card using bus-master DMA.
- // pBuffer if the data to transfer (or to receive data), dwBytes - size of data
- // fIsRead is TRUE for read (PCI card --> system memory), or FALSE for write ( memory --> PCI card)
- // addr local address on PCI card
- void IO_DMATransferBuffer(PVOID pBuffer, DWORD dwBytes, BOOL fIsRead, DWORD dwAddr)
- {
- WD_DMA dma;
- DWORD i;
- DWORD dwSumBytes;
-
- BZERO(dma);
- dma.pUserAddr = pBuffer;
- dma.dwBytes = dwBytes;
- dma.dwOptions = 0;
-
- // lock region in memory & get page list
- WD_DMALock(hWD,&dma);
-
- // program page transfer list on PCI bus master card
- dwSumBytes = 0;
- for (i=0; i<dma.dwPages; i++)
- {
- IO_Write32BitRegister(MY_REG_DMA_PAGES + i*12 + 0, (DWORD) dma.Page[i].pPhysicalAddr);
- IO_Write32BitRegister(MY_REG_DMA_PAGES + i*12 + 4, dwAddr + dwSumBytes);
- IO_Write32BitRegister(MY_REG_DMA_PAGES + i*12 + 8, dma.Page[i].dwBytes);
- dwSumBytes += dma.Page[i].dwBytes;
- }
-
- // write the number of pages to transfer and direction of transfer
- IO_Write32BitRegister(MY_REG_DMA_STATUS, dma.dwPages | (fIsRead ? 0x1000 : 0));
-
- // wait for for status register to indicate transfer compleate here.
- // you can use the interrupt routine for non-busy wait (if the card enables interrupt
- // indication for end of transfer).
-
- WD_DMAUnlock(hWD,&dma);
- }
-
- // transfer data to/from PCI card NOT using DMA.
- // pBuffer if the data to transfer (or to receive data), dwBytes - size of data
- // fIsRead is TRUE for read (PCI card --> system memory), or FALSE for write ( memory --> PCI card)
- // addr local address on PCI card
- void IO_TransferBuffer(PVOID pBuffer, DWORD dwBytes, BOOL fIsRead, DWORD dwAddr)
- {
- WD_TRANSFER trans;
-
- BZERO(trans);
- if (fIsRead)
- trans.cmdTrans = RM_SDWORD; // Read Memory String DWORD
- else trans.cmdTrans = WM_SDWORD; // Write Memory String DWORD
- trans.dwPort = G_baseMemoryTrns + dwAddr;
- trans.Data.pBuffer = pBuffer;
- trans.dwBytes = dwBytes;
-
- // if fAutoinc==TRUE then read/write will run through an address range on the card
- // if fAutoinc==FALSE then read/write will perform on the same address of the card
- // (usually used for FIFO where all reads/writes are to the same register)
- trans.fAutoinc = TRUE;
-
- trans.dwOptions = 0;
-
- WD_Transfer (hWD, &trans);
-
- // this function could also be implemeted directly with memcpy().
- // for example, to read a memory region:
- // memcpy (pBuffer, (PVOID) (dwAddr + G_baseMemory), dwBytes);
- }
-
- int main(int argc, char *argv[])
- {
- IO_Open();
-
- IO_DetectCard();
-
- // call your main card routine program
- // in your program you can use IO_DMATransferBuffer() for DMA read/write,
- // or IO_TransferBuffer() to do the same thing without DMA,
- // IO_Read32BitRegister() & IO_Write32BitRegister for single 32bit read/write
- MY_CardMainDriver();
-
- IO_Close();
-
- return 0;
- }
-
-
-
-
-
-
-